package com.prtek.reminder.activity;

import android.app.AlertDialog;
import android.content.Context;
import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.OnClick;
import com.alibaba.fastjson.JSON;
import com.bigkoo.pickerview.builder.TimePickerBuilder;
import com.bigkoo.pickerview.listener.OnTimeSelectChangeListener;
import com.bigkoo.pickerview.listener.OnTimeSelectListener;
import com.bigkoo.pickerview.view.TimePickerView;
import com.prtek.iis.core.PrtekIIS;
import com.prtek.iis.core.PrtekIISUtils;
import com.prtek.iis.event.GestureEvent;
import com.prtek.iis.event.GestureEventListener;
import com.prtek.iis.event.GestureEventOptions;
import com.prtek.iis.gesture.Gesture;
import com.prtek.iis.grammar.Expression;
import com.prtek.iis.grammar.JoinExpressionGroup;
import com.prtek.iis.grammar.OrExpressionGroup;
import com.prtek.reminder.Constant;
import com.prtek.reminder.R;
import com.prtek.reminder.bean.Notes;
import com.prtek.reminder.bean.NotesJoinUser;
import com.prtek.reminder.bean.User;
import com.prtek.reminder.bean.UserExpression;
import com.prtek.reminder.listener.OnConfirmClickListener;
import com.prtek.reminder.listener.OnRecordCompleteListener;
import com.prtek.reminder.model.MainModel;
import com.prtek.reminder.model.ReminderDaoImpl;
import com.prtek.reminder.model.SpeechEventModelImpl;
import com.prtek.reminder.model.UserManager;
import com.prtek.reminder.presenter.RemindEditPresenter;
import com.prtek.reminder.presenter.RemindEditPresenterImpl;
import com.prtek.reminder.util.APPExpress;
import com.prtek.reminder.util.AudioPlayer;
import com.prtek.reminder.util.AudioRecorder;
import com.prtek.reminder.util.Countdown;
import com.prtek.reminder.util.DateUtil;
import com.prtek.reminder.util.FileUtils;
import com.prtek.reminder.util.IoUtil;
import com.prtek.reminder.util.LogUtil;
import com.prtek.reminder.util.ToastUtil;
import com.prtek.reminder.util.io.ThreadExecutor;
import com.prtek.reminder.view.RemindEditView;
import com.prtek.reminder.view.SelectUserDialog;
import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import static com.prtek.reminder.Constant.DESC_AUDIO;
import static com.prtek.reminder.Constant.DESC_TEXT;

/**
 * Created by jarly on 2018/9/8.
 */

public class RemindEditActivity extends BaseActivity
    implements OnTimeSelectListener, OnTimeSelectChangeListener, OnConfirmClickListener,
    View.OnFocusChangeListener, OnRecordCompleteListener, RemindEditView {

  public static final int TIMES = 20;
  public static final String VAD_EOS = "3000";

  @BindView(R.id.remind_desc) EditText mDescEt;
  @BindView(R.id.remind_user_tv) TextView mRemindUserTv;
  @BindView(R.id.cofirm_btn) Button mCofirmBtn;
  @BindView(R.id.date_tv) TextView mDateTv;
  @BindView(R.id.desc_tv) TextView mDescTv;
  @BindView(R.id.desc_container) LinearLayout mDescContainer;
  @BindView(R.id.cancle_btn) Button mCancleBtn;
  @BindView(R.id.audio_tv) TextView mAudioTv;
  @BindView(R.id.audio_time) TextView mAudioTime;
  @BindView(R.id.audio_container) LinearLayout mAudioContainer;
  @BindView(R.id.audio_icon) ImageView mAudioIcon;
  @BindView(R.id.audio_text) TextView mAudioTextTv;
  @BindView(R.id.tip_tv) TextView mTipTv;
  private TimePickerView pvTime;
  private List<User> mContactSelectedList = new ArrayList<>();
  private ArrayList<User> mUserList;
  private String mEndDate;
  private SelectUserDialog mDialog;
  private InputMethodManager mImm;
  private static final DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
  private static final Pattern pattern = Pattern.compile(
      "^((((1[6-9]|[2-9]\\d)\\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2})"
          + "年(0?[13456789]|1[012])"
          + "月(0?[1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-0?2-(0?[1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))日$");

  private String mUserText;
  private String mAudioRecorderPath;
  private int mDescType;
  private AudioRecorder mAudioRecorder;
  private RemindEditPresenter mPresenter;
  private String mDateFormat;
  private AudioPlayer mAudioPlayer;
  private boolean mAudioPlaying;
  private String mCountDown;
  private PrtekIIS mPrtekIIS;
  private APPExpress mAPPExpress;
  private long mEndTime;

  @Override protected void initData() {
    mUserList = UserManager.getUserList();
    mPresenter = new RemindEditPresenterImpl(this, ReminderDaoImpl.getInstance(),
        new SpeechEventModelImpl());
    mPresenter.start(mContext);
    final ThreadExecutor threadExecutor = ThreadExecutor.getInstance();
    threadExecutor.io().execute(() -> {
      final Expression expression = getExpression();
      threadExecutor.main()
          .execute(() -> mPresenter.setupSpeechEventListener(mContext, expression));
    });

    mImm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    mDescEt.setOnFocusChangeListener(this);
    mDescEt.addTextChangedListener(mWatcher);
    mTipTv.postDelayed(() -> mTipTv.setVisibility(View.GONE), 8000);
  }

  @Override protected void onStart() {
    super.onStart();
    setupGestureListener();
  }

  @Override protected void onStop() {
    super.onStop();
    mPrtekIIS.removeEventListener(mGestureEventListener);
    mPrtekIIS.release();
    stopAudioRecord();
    mPresenter.removeSpeechEventListener();
  }

  @Override protected void onResume() {
    super.onResume();
    mAudioRecorder = AudioRecorder.getInstance(this);
  }

  @Override protected void onPause() {
    super.onPause();
    if (mAudioPlayer != null) {
      mAudioPlayer.stop();
    }
  }

  private void setupGestureListener() {
    mPrtekIIS = PrtekIISUtils.createPrtekIIS(mContext.getApplicationContext());
    GestureEventOptions options = new GestureEventOptions();
    options.setRunOnUiThread();
    options.addGestureAction(Gesture.ACTION_HAND_MOVE);
    mPrtekIIS.addEventListener(mGestureEventListener, GestureEvent.TYPE_STARTED, options);
  }

  @Override protected void init() {
    final String json = IoUtil.inputStreamToString(getResources().openRawResource(R.raw.express));
    final Map<String, Long> map = (Map<String, Long>) JSON.parse(json);
    mAPPExpress = APPExpress.getInstance();
    mAPPExpress.putContext(map);

    Calendar start = Calendar.getInstance();
    Calendar deadline = Calendar.getInstance();
    deadline.set(2999, 1, 31);
    pvTime = new TimePickerBuilder(this, this).setType(
        new boolean[] { true, true, true, true, true, false })
        .isDialog(true)
        .setRangDate(start, deadline)
        .setTimeSelectChangeListener(this)
        .build();
    mDateFormat = mContext.getString(R.string.date_format);
  }

  private TextWatcher mWatcher = new TextWatcher() {

    @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    }

    @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    }

    @Override public void afterTextChanged(Editable editable) {
      if (editable.length() > 0) {
        setAudioIconVisible(false);
      }
    }
  };

  @Override public void onBackPressed() {
    if (mAudioRecorder == null || !mAudioRecorder.isRunning()) {
      super.onBackPressed();
      return;
    }
    AlertDialog.Builder deleteDialog = new AlertDialog.Builder(this);
    deleteDialog.setTitle(R.string.title)
        .setMessage(R.string.back_tip)
        .setPositiveButton(R.string.pickerview_cancel, (dialog, i) -> {
        })
        .setNegativeButton(R.string.pickerview_submit, (dialog, i) -> {
          mCountdown.stop();
          mAudioRecorder.cancel();
          dialog.dismiss();
          finish();
        })
        .create()
        .show();
  }

  @OnClick({
      R.id.remind_user_tv, R.id.cofirm_btn, R.id.date_tv, R.id.cancle_btn, R.id.desc_tv,
      R.id.audio_tv, R.id.audio_icon
  }) public void onViewClicked(View view) {
    switch (view.getId()) {
      case R.id.remind_user_tv:
        initSelectUserDialog();
        break;
      case R.id.cofirm_btn:
        saveRemind();
        break;
      case R.id.cancle_btn:
        finish();
        break;
      case R.id.date_tv:
        pvTime.show();
        break;
      case R.id.desc_tv:
        remindDesc();
        break;
      case R.id.audio_tv:
        remindAudio();
        break;
      case R.id.audio_icon:
        if (mDescType == DESC_TEXT || TextUtils.isEmpty(mAudioRecorderPath)) {
          return;
        }

        mAudioPlayer = AudioPlayer.getInstance();
        if (mAudioPlaying) {
          mAudioPlayer.stop();
        } else {
          mAudioPlayer.startPlayAudio(mAudioIcon.getDrawable(), mAudioRecorderPath);
        }
        mAudioPlaying = !mAudioPlaying;
        break;
      default:
        break;
    }
  }

  private void saveRemind() {
    String desc = mDescEt.getText().toString().trim();

    if (mDescType == DESC_AUDIO && mAudioRecorderPath != null) {
      File file = new File(mAudioRecorderPath);
      if (!file.exists()) {
        ToastUtil.showTip(mContext, "保存失败,找不到语音文件");
        return;
      }
      desc = mAudioTextTv.getText().toString();
      LogUtil.i("content: " + desc + "\npath: " + mAudioRecorderPath);
    } else if (mDescType == DESC_TEXT) {

      if (TextUtils.isEmpty(desc)) {
        ToastUtil.showTip(mContext, "\'提醒内容\'不能为空");
        mDescEt.requestFocus();
        return;
      }
      mAudioRecorderPath = "";
    }

    if (TextUtils.isEmpty(mEndDate)) {
      ToastUtil.showTip(mContext, "保存失败,请选择提醒日期");
      return;
    }

 /*   if (!pattern.matcher(mEndDate).matches()) {
      ToastUtil.showTip(mContext, "保存失败,日期格式错误!YYYY年MM月DD日");
      return;
    }*/

    if (mContactSelectedList.isEmpty()) {
      ToastUtil.showTip(mContext, "保存失败,至少选择一个用户");
      return;
    }

    final long time = MainModel.mCalendar.getTime().getTime();

  /*  Date date;
    df.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
    try {
      date = df.parse(mEndDate);
    } catch (Exception e) {
      date = new Date();
      e.printStackTrace();
    }*/

    if (mEndTime < time) {
      ToastUtil.showTip(mContext, "保存失败,提醒日期不能低于创建日期");
      return;
    }

    Notes notes = new Notes();
    notes.setExpireDate(mEndDate);
    notes.setStartTimes(new Date());
    notes.setEndTimes(new Date(mEndTime));
    notes.setDesc(desc);
    notes.setDescType(mDescType);
    notes.setFilePath(mAudioRecorderPath);
    notes.setUserNames(mUserText);
    mPresenter.saveNotes(notes);
    final Long id = notes.getId();
    for (User user : mContactSelectedList) {
      NotesJoinUser joinUser = new NotesJoinUser();
      joinUser.setNotesId(id);
      joinUser.setRemindUserId(user.getUserId());
      mPresenter.addNotesJoinUser(joinUser);
    }
    finish();
  }

  private void initSelectUserDialog() {
    if (mDialog == null) {
      mDialog = new SelectUserDialog(this);
      mDialog.setCancelable(true);
      mDialog.setOnConfirmClickListener(this);
    }
    mDialog.show();
    for (User user : mUserList) {
      if (mContactSelectedList.contains(user)) {
        user.setSelected(true);
        mDialog.setSelectUsers(user);
        continue;
      }
      user.setSelected(false);
    }
    mDialog.setData(mUserList);
  }

  private void selectedUser() {

    StringBuilder sbf = new StringBuilder(getString(R.string.select_user));
    boolean end = false;
    for (User user : mContactSelectedList) {
      if (end) {
        sbf.append("、");
      }
      sbf.append(user.getName());
      end = true;
    }
    mUserText = sbf.toString();
    mRemindUserTv.setText(mUserText);
  }

  @Override public void onTimeSelect(Date date, View v) {
    mEndTime = date.getTime();
    mEndDate = DateUtil.getDisplayTime(mEndTime);
    mDateTv.setText(String.format(mDateFormat, mEndDate));
    pvTime.dismiss();
  }

  @Override public void onTimeSelectChanged(Date date) {
  }

  @Override public void onConfirmClick(List<User> userList) {
    mContactSelectedList.clear();
    mContactSelectedList.addAll(userList);
    selectedUser();
  }

  @Override public void onFocusChange(View view, boolean hasFocus) {
    if (hasFocus) {
      ((EditText) view).setInputType(InputType.TYPE_CLASS_TEXT);
      mImm.showSoftInput(view, InputMethodManager.RESULT_UNCHANGED_SHOWN);
    }
    mDescTv.setTextColor(hasFocus ? 0xFFFFFFFF : 0xFFE0E0E0);
    mDescContainer.setBackgroundResource(hasFocus ? R.drawable.msg_item_focused_shape : 0);
  }

  @Override public void remindDate() {
    mPresenter.setSpeechType(Constant.TYPE_DATE);
    mPresenter.setParam(VAD_EOS, "0", "");
    mPresenter.startRecognizer(null);
  }

  @Override public void remindDesc() {

    mPresenter.setSpeechType(Constant.TYPE_DESC);
    mDescEt.setText(null);
    setAudioIconVisible(false);
    mPresenter.setParam(VAD_EOS, "0", "");
    mPresenter.startRecognizer(null);
  }

  @Override public void remindAudio() {
    final String mountedDirs = FileUtils.getAppCacheDir(this.getApplication());

    if (TextUtils.isEmpty(mountedDirs)) {
      showTip("启动录音失败,未找到外部存储设备!");
      return;
    }

    mAudioRecorder.start();
    mCountdown.start();
    mAudioRecorder.setOnRecordCompleteListener(this);
  }

  private Countdown mCountdown = new Countdown(TIMES) {

    @Override protected void onTick(int tick) {
      if (tick == 0) {
        mAudioRecorder.stop();
        return;
      }
      mCountDown = mContext.getString(R.string.count_down);
      showTip(String.format(mCountDown, tick));
    }
  };

  @Override public void selectUser() {
    mPresenter.setSpeechType(Constant.TYPE_USER);
    if (mDialog == null || !mDialog.isShowing()) {
      initSelectUserDialog();
    }
    mPresenter.setParam(VAD_EOS, "0", "");
    mPresenter.startRecognizer(null);
  }

  @Override public void remindSave() {

    saveRemind();
  }

  @Override public void remindConfirm() {
    if (mDialog != null && mDialog.isShowing()) {
      mDialog.onConfirm();
      mDialog.dismiss();
      return;
    }
  }

  @Override public void remindCancel() {
    if (mDialog != null && mDialog.isShowing()) {
      mDialog.onCancel();
      mDialog.dismiss();
      return;
    }
    finish();
  }

  @Override public void onRecordComplete(int length) {
    setAudioIconVisible(true);
    mDescEt.setText(null);
    mAudioTime.setText(String.format(getString(R.string.audio_second), length));
  }

  private void setAudioIconVisible(boolean visible) {
    mAudioIcon.setVisibility(visible ? View.VISIBLE : View.GONE);
    mAudioTime.setVisibility(visible ? View.VISIBLE : View.GONE);
    mDescType = visible ? DESC_AUDIO : DESC_TEXT;

    if (!TextUtils.isEmpty(mAudioRecorderPath) && !visible) {
      mAudioTextTv.setText(null);
      FileUtils.deleteFile(mAudioRecorderPath);
    }
  }

  @Override public void onRecordComplete(String filePath) {
    runOnUiThread(() -> {
      final File file = new File(filePath);
      if (file.exists()) {
        mAudioTextTv.setText(null);
        mPresenter.setSpeechType(Constant.TYPE_AUDIO);
        mAudioRecorderPath = filePath;
        mPresenter.setParam(VAD_EOS, "1", "");
        mPresenter.startRecognizer(file);
      }
    });
    LogUtil.i("AudioFile : " + filePath);
  }

  private GestureEventListener mGestureEventListener = (event, result) -> {
    stopPlayer();
    stopAudioRecord();
  };

  @Override protected int getLayoutId() {
    return R.layout.activity_remind;
  }

  @Override protected Expression getExpression() {
    final String[] commandArr = getResources().getStringArray(R.array.voice_command);
    final OrExpressionGroup expressions = new OrExpressionGroup();
    for (User user : mUserList) {
      expressions.add(new UserExpression(user.getName(), user.getUserId()));
    }
    return new JoinExpressionGroup().add(expressions.add(commandArr));
  }

  @Override protected void onDestroy() {
    super.onDestroy();
    mPresenter.destroy();
  }

  private void stopAudioRecord() {
    if (mCountdown != null) {
      mCountdown.stop();
    }

    if (mAudioRecorder != null) {
      mAudioRecorder.stop();
    }
  }

  @Override public void showTip(String tip) {
    ToastUtil.showTip(mContext, tip);
  }

  @Override public void setDescText(String content) {
    mDescEt.append(content);
    mDescEt.setSelection(mDescEt.length());
  }

  @Override public void addSelectUser(String userName) {
    if (mDialog != null && mDialog.isShowing()) {
      mDialog.addSelectUser(userName);
    }
  }

  @Override public void setAudioText(String audioContent) {
    mAudioTextTv.setText(String.format(mContext.getString(R.string.audio_tag), audioContent));
  }

  @Override public void setDateText(String s) {
    LogUtil.i("text: "+s);
    final long millis = System.currentTimeMillis();
    mEndDate = "";
    try {
      final long execute = mAPPExpress.execute(s);
      mEndTime = execute + millis;
      mEndDate = DateUtil.getDisplayTime(mEndTime);
    } catch (Exception e) {
      e.printStackTrace();
      showTip("未能识别时间格式:x分钟后|x小时后|明天|后天");
    }

    mDateTv.setText(String.format(mDateFormat, mEndDate));
  }

  @Override public void stopPlayer() {
    if (mAudioPlaying) {
      mAudioPlayer.stop();
      mAudioPlaying = false;
    }
  }
}
